//输入驱动
#ifndef _IN_DEV_H_
#define _IN_DEV_H_

#include <lvgl.h>

#include "main.h"

/**********************
 *  STATIC VARIABLES
 **********************/
lv_indev_t *indev_touchpad;
lv_indev_t *indev_mouse;
lv_indev_t *indev_keypad;
lv_indev_t *indev_encoder;

lv_indev_drv_t indev_drv;

lv_group_t *group;

// #define TOUCH_INDEV
// #define MOUSE_INDEV
//#define ENCODER_INDEV
#define BUTTON_INDEV

#ifdef TOUCH_INDEV

static void touchpad_init(void);
static void touchpad_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data);
static bool touchpad_is_pressed(void);
static void touchpad_get_xy(lv_coord_t *x, lv_coord_t *y);

void lv_port_indev_init(void) {
  /* Here you will find example implementation of input devices supported by
   * LittelvGL:
   *  - Touchpad
   *  - Mouse (with cursor support)
   *  - Keypad (supports GUI usage only with key)
   *  - Encoder (supports GUI usage only with: left, right, push)
   *  - Button (external buttons to press points on the screen)
   *
   *  The `..._read()` function are only examples.
   *  You should shape them according to your hardware
   */

  /*------------------
   * Touchpad
   * -----------------*/

  /*Initialize your touchpad if you have*/
  touchpad_init();

  /*Register a touchpad input device*/
  lv_indev_drv_init(&indev_drv);
  indev_drv.type = LV_INDEV_TYPE_POINTER;
  indev_drv.read_cb = touchpad_read;
  indev_touchpad = lv_indev_drv_register(&indev_drv);
}

/*------------------
 * Touchpad
 * -----------------*/

/*Initialize your touchpad*/
static void touchpad_init(void) {
  /*Your code comes here*/
  ESP32Encoder::useInternalWeakPullResistors = UP;
  encoder.attachSingleEdge(EC11_A_PIN, EC11_B_PIN);
  encoder.setCount(0);

  pinMode(EC11_K_PIN, INPUT_PULLUP);
}

/*Will be called by the library to read the touchpad*/
static void touchpad_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data) {
  static lv_coord_t last_x = 0;
  static lv_coord_t last_y = 0;

  /*Save the pressed coordinates and the state*/
  if (touchpad_is_pressed()) {
    touchpad_get_xy(&last_x, &last_y);
    data->state = LV_INDEV_STATE_PR;
  } else {
    data->state = LV_INDEV_STATE_REL;
  }

  Serial.printf("x: %d,y: %d\n", last_x, last_y);
  /*Set the last pressed coordinates*/
  data->point.x = last_x;
  data->point.y = last_y;
}

/*Return true is the touchpad is pressed*/
static bool touchpad_is_pressed(void) {
  /*Your code comes here*/
  if (digitalRead(EC11_K_PIN) == LOW)
    return true;
  else if (digitalRead(EC11_K_PIN) == HIGH)
    return false;
}

/*Get the x and y coordinates if the touchpad is pressed*/
static void touchpad_get_xy(lv_coord_t *x, lv_coord_t *y) {
  /*Your code comes here*/
  (*x) = 60;
  (*y) = 101;
}

#endif

#ifdef MOUSE_INDEV

static void mouse_init(void);
static void mouse_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data);
static bool mouse_is_pressed(void);
static void mouse_get_xy(lv_coord_t *x, lv_coord_t *y);

void lv_port_indev_init(void) {
  /* Here you will find example implementation of input devices supported by
   * LittelvGL:
   *  - Touchpad
   *  - Mouse (with cursor support)
   *  - Keypad (supports GUI usage only with key)
   *  - Encoder (supports GUI usage only with: left, right, push)
   *  - Button (external buttons to press points on the screen)
   *
   *  The `..._read()` function are only examples.
   *  You should shape them according to your hardware
   */

  /*------------------
   * Mouse
   * -----------------*/

  /*Initialize your touchpad if you have*/
  mouse_init();

  /*Register a mouse input device*/
  lv_indev_drv_init(&indev_drv);
  indev_drv.type = LV_INDEV_TYPE_POINTER;
  indev_drv.read_cb = mouse_read;
  indev_mouse = lv_indev_drv_register(&indev_drv);

  /*Set cursor. For simplicity set a HOME symbol now.*/
  lv_obj_t *mouse_cursor = lv_img_create(lv_disp_get_scr_act(NULL));
  lv_img_set_src(mouse_cursor, LV_SYMBOL_OK);
  lv_indev_set_cursor(indev_mouse, mouse_cursor);
}

/*------------------
 * Mouse
 * -----------------*/

/*Initialize your mouse*/
static void mouse_init(void) {
  /*Your code comes here*/
  ESP32Encoder::useInternalWeakPullResistors = UP;
  encoder.attachSingleEdge(EC11_A_PIN, EC11_B_PIN);
  encoder.setCount(0);

  pinMode(EC11_K_PIN, INPUT_PULLUP);
}

/*Will be called by the library to read the mouse*/
static void mouse_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data) {
  /*Get the current x and y coordinates*/
  mouse_get_xy(&data->point.x, &data->point.y);

  /*Get whether the mouse button is pressed or released*/
  if (mouse_is_pressed()) {
    data->state = LV_INDEV_STATE_PR;
  } else {
    data->state = LV_INDEV_STATE_REL;
  }
  Serial.printf("x: %d,y: %d,state:%d\n", data->point.x, data->point.y,
                data->state);
}

/*Return true is the mouse button is pressed*/
static bool mouse_is_pressed(void) {
  /*Your code comes here*/
  if (digitalRead(EC11_K_PIN) == LOW)
    return true;
  else if (digitalRead(EC11_K_PIN) == HIGH)
    return false;
}

/*Get the x and y coordinates if the mouse is pressed*/
static void mouse_get_xy(lv_coord_t *x, lv_coord_t *y) {
  /*Your code comes here*/
  static int last_count = 0;

  if (encoder.getCount() != last_count) {
    if (encoder.getCount() - last_count > 0) {
      (*x) -= 3;
    } else if (encoder.getCount() - last_count < 0) {
      (*x) += 3;
    }
    last_count = encoder.getCount();
  }

  (*x) = (*x) < 0 ? 0 : (*x);
  (*x) = (*x) > 240 ? 240 : (*x);

  (*y) = (*y) < 0 ? 0 : (*y);
  (*y) = (*y) > 240 ? 135 : (*y);

  (*y) = 101;
}

#endif

#ifdef ENCODER_INDEV

static int32_t encoder_diff;
static lv_indev_state_t encoder_state;

static void encoder_init(void);
static void encoder_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data);
static void encoder_handler(void);

void lv_port_indev_init(void) {
  /* Here you will find example implementation of input devices supported by
   * LittelvGL:
   *  - Touchpad
   *  - Mouse (with cursor support)
   *  - Keypad (supports GUI usage only with key)
   *  - Encoder (supports GUI usage only with: left, right, push)
   *  - Button (external buttons to press points on the screen)
   *
   *  The `..._read()` function are only examples.
   *  You should shape them according to your hardware
   */

  /*------------------
   * Encoder
   * -----------------*/

  /*Initialize your encoder if you have*/
  encoder_init();

  /*Register a encoder input device*/
  lv_indev_drv_init(&indev_drv);
  indev_drv.type = LV_INDEV_TYPE_ENCODER;

  indev_drv.read_cb = encoder_read;
  indev_encoder = lv_indev_drv_register(&indev_drv);

  /* 创建group */
  group = lv_group_create();
  lv_indev_set_group(indev_encoder, group);
}

/*------------------
 * Encoder
 * -----------------*/

/* Initialize your keypad */
static void encoder_init(void) {
  /*Your code comes here*/
  ESP32Encoder::useInternalWeakPullResistors = UP;
  encoder.attachSingleEdge(EC11_A_PIN, EC11_B_PIN);
  encoder.setCount(0);

  pinMode(EC11_K_PIN, INPUT_PULLUP);
}

/*Will be called by the library to read the encoder*/
static void encoder_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data) {
  encoder_handler();
  data->enc_diff = encoder_diff;
  data->state = encoder_state;

  Serial.printf("x: %d,y: %d\n", data->enc_diff, data->state);
}

/*Call this function in an interrupt to process encoder events (turn, press)*/
static void encoder_handler(void) {
  static int last_count = 0;

  encoder_state = LV_INDEV_STATE_REL;
  encoder_diff = 0;

  if (encoder.getCount() != last_count) {
    encoder_state = LV_INDEV_STATE_REL;
    if (encoder.getCount() - last_count > 0) {
      encoder_diff = -1;
    } else if (encoder.getCount() - last_count < 0) {
      encoder_diff = 1;
    }
    last_count = encoder.getCount();
  }

  if (digitalRead(EC11_K_PIN) == LOW) {
    encoder_state = LV_INDEV_STATE_PR;
  } else if (digitalRead(EC11_K_PIN) == HIGH) {
    encoder_state = LV_INDEV_STATE_REL;
  }
}

#endif

#ifdef BUTTON_INDEV

static int32_t encoder_diff;
static lv_indev_state_t encoder_state;

static void encoder_init(void);
static void encoder_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data);
static void encoder_handler(void);

void lv_port_indev_init(void) {
  /* Here you will find example implementation of input devices supported by
   * LittelvGL:
   *  - Touchpad
   *  - Mouse (with cursor support)
   *  - Keypad (supports GUI usage only with key)
   *  - Encoder (supports GUI usage only with: left, right, push)
   *  - Button (external buttons to press points on the screen)
   *
   *  The `..._read()` function are only examples.
   *  You should shape them according to your hardware
   */

  /*------------------
   * Encoder
   * -----------------*/

  /*Initialize your encoder if you have*/
  encoder_init();

  /*Register a encoder input device*/
  lv_indev_drv_init(&indev_drv);
  indev_drv.type = LV_INDEV_TYPE_ENCODER;

  indev_drv.read_cb = encoder_read;
  indev_encoder = lv_indev_drv_register(&indev_drv);

  /* 创建group */
  lv_group_t * group = lv_group_create();
  lv_indev_set_group(indev_encoder, group);
}

/*------------------
 * Encoder
 * -----------------*/

/* Initialize your keypad */
static void encoder_init(void) {
  /*Your code comes here*/

  pinMode(EC11_A_PIN, INPUT_PULLUP);
  pinMode(EC11_B_PIN, INPUT_PULLUP);
  pinMode(EC11_K_PIN, INPUT_PULLUP);
}

/*Will be called by the library to read the encoder*/
static void encoder_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data) {
  encoder_handler();
  data->enc_diff = encoder_diff;
  data->state = encoder_state;

  // Serial.printf("x: %d,y: %d\n", data->enc_diff, data->state);
}

/*Call this function in an interrupt to process encoder events (turn, press)*/
static void encoder_handler(void) {
  encoder_state = LV_INDEV_STATE_REL;
  encoder_diff = 0;

  if (digitalRead(EC11_A_PIN) == LOW && digitalRead(EC11_B_PIN) == HIGH) {
    delay(5);
    if (digitalRead(EC11_A_PIN) == LOW && digitalRead(EC11_B_PIN) == HIGH) {
      encoder_diff = -1;
      encoder_state = LV_INDEV_STATE_REL;
      long last_time = millis();
      while (digitalRead(EC11_A_PIN) == LOW) {
        if (millis() - last_time > key_long_press_time) break;
      }
    }
  }

  if (digitalRead(EC11_B_PIN) == LOW && digitalRead(EC11_A_PIN) == HIGH) {
    delay(5);
    if (digitalRead(EC11_B_PIN) == LOW && digitalRead(EC11_A_PIN) == HIGH) {
      encoder_diff = 1;
      encoder_state = LV_INDEV_STATE_REL;
      long last_time = millis();
      while (digitalRead(EC11_B_PIN) == LOW) {
        if (millis() - last_time > key_long_press_time) break;
      }
    }
  }

  if (digitalRead(EC11_K_PIN) == LOW) {
    encoder_state = LV_INDEV_STATE_PR;
  } else if (digitalRead(EC11_K_PIN) == HIGH) {
    encoder_state = LV_INDEV_STATE_REL;
  }
}

#endif

#endif